package cn.dlc.com.config;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooDefs.Ids;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 配置中心
 * @author Administrator
 *
 */
public class ConfigCenter {

	private Config config = new Config();
	
	// 创建连接对象
	private ZooKeeper zkClient;
			
	/**
	 * 初始化配置节点信息，也就是将配置信息写入节点，配置中心调用这个写入数据
	 * @param zkUrl zookeeper服务器地址
	 * @param nodePath 节点
	 * @param config 配置信息
	 * @throws Exception
	 */
	public void initConfig(String zkUrl, String nodePath, Config config) throws Exception{
		// 初始化连接对象
		zkClient = new ZooKeeper(zkUrl, 2000, new Watcher() {
			@Override
			public void process(WatchedEvent event) {
				// 不做监听，因为是服务端调用
			}
		});
		
		ObjectMapper objectMapper = new ObjectMapper();
		// 判断节点是否存在
		if(zkClient.exists(nodePath,null) == null) {
			// 创建一个持久化的节点，同时往里面写数据
			zkClient.create(nodePath, 
					objectMapper.writeValueAsString(config).getBytes(), 
					Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			System.out.println("创建一个节点成功。。。。。");
		} else {
			// -1表示最新的版本，直接写入数据
			zkClient.setData(nodePath, 
					objectMapper.writeValueAsString(config).getBytes(), -1);
			System.out.println("节点存在，修改节点数据。。。。。");
		}
	}
	
	/**
	 * 更新配置数据
	 * @param nodePath
	 * @throws Exception
	 */
	public void updateConfig(String nodePath, Config config) throws Exception {
		ObjectMapper objectMapper = new ObjectMapper();
		zkClient.setData(nodePath, 
				objectMapper.writeValueAsString(config).getBytes(),-1);
	}
	
	/**
	 * 创建连接、获取节点，并且监听，第二次获取就不是默认的节点了
	 * @return
	 */
	public Config getConfig(String zkUrl, String nodePath) throws Exception{
		System.out.println("zk: " + zkUrl);
		// 首先创建连接，
		zkClient = new ZooKeeper(zkUrl, 2000, new Watcher() {
			@Override
			public void process(WatchedEvent event) {
				try {
					// 客户端监听节点数据变化
					if(event.getType().equals(EventType.NodeDataChanged)) {
						byte[] data = zkClient.getData(nodePath, true, null);
						// 获取到配置信息，数据将被返回
						config = convertConfig(data);
						
					} else if(event.getType().equals(EventType.NodeDeleted )) {
						// 节点被删掉之后触发这个监听
						System.out.println("节点数据被删除");
					}
				}catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		
		// 从配置中心里面获取数据，本地没有这一份数据库的连接数据
		byte[] data = zkClient.getData(nodePath, true, null);
		config = convertConfig(data);
		return config;
	}
	
	/**
	 * 将byte[]转换为对象
	 * @param data
	 * @return
	 * @throws Exception
	 */
	private Config convertConfig(byte[] data) throws Exception {
		
		// 数据格式转换，这里不知道为什么保存之后前面有一点乱码
		String configStr = new String(data);
		configStr = configStr.substring(configStr.indexOf("{"), configStr.lastIndexOf("}") + 1);
		System.out.println("获取到的节点信息：" + configStr);
		// 解析数据，初始化数据配置的对象
		ObjectMapper objectMapper = new ObjectMapper();
		Config config = objectMapper.readValue(configStr, Config.class);
		return config;
	}
}
